package com.xiaomo.gitee.datamanager.security.filter;

import com.xiaomo.gitee.datamanager.SpringBeanUtils;
import com.xiaomo.gitee.datamanager.common.result.Code;
import com.xiaomo.gitee.datamanager.common.result.Result;
import com.xiaomo.gitee.datamanager.entity.User;
import com.xiaomo.gitee.datamanager.mapper.UserMapper;
import com.xiaomo.gitee.datamanager.security.service.impl.UserServiceImpl;
import com.xiaomo.gitee.datamanager.util.HttpUtils;
import com.xiaomo.gitee.datamanager.util.JwtUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import java.io.IOException;

public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

    private JwtUtils jwtUtils;
    private UserMapper userMapper;
    private UserServiceImpl userService;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
        jwtUtils = SpringBeanUtils.getApplicationContext().getBean(JwtUtils.class);
        userMapper = SpringBeanUtils.getApplicationContext().getBean(UserMapper.class);
        userService = SpringBeanUtils.getApplicationContext().getBean(UserServiceImpl.class);
    }

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager, AuthenticationEntryPoint authenticationEntryPoint) {
        super(authenticationManager, authenticationEntryPoint);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String headerJwt = JwtUtils.getJwtTokenFromHttpHeader(request);
        if (verifyString(headerJwt)) {
            if (!jwtUtils.isValidToken(headerJwt)) {
                HttpUtils.writeJson(response, Result.fail(Integer.parseInt(Code.LOGIN_EXPIRED),Code.getInfo(Code.LOGIN_EXPIRED)));
                return;
            }
            if ("/login-api".equalsIgnoreCase(request.getRequestURI())) {
                HttpUtils.writeJson(response,Result.fail(Integer.parseInt(Code.USER_HAS_LOGIN),Code.getInfo(Code.USER_HAS_LOGIN)));
                return;
            }
            authenticationPass(headerJwt);
        } else {
            String cookieInfo = request.getHeader("no-cookie");
            if (!verifyString(cookieInfo)) {
                String cookieJwt = null;
                if (request.getCookies() != null) {
                    for (Cookie cookie : request.getCookies()) {
                        if (cookie.getName().equals(JwtUtils.TOKEN_HEADER)) {
                            cookieJwt = cookie.getValue();
                            break;
                        }
                    }
                }
                if (!verifyString(cookieJwt)) {
                    chain.doFilter(request, response);
                    return;
                }
                if (!jwtUtils.isValidToken(cookieJwt)) {
                    Cookie cookie = new Cookie(JwtUtils.TOKEN_HEADER, null);
                    cookie.setMaxAge(0);
                    response.addCookie(cookie);
                    response.sendRedirect("/login");
                    return;
                }
                authenticationPass(cookieJwt);
            }
        }
        chain.doFilter(request, response);
    }

    private boolean verifyString(String str) {
        return !(str==null || str.isBlank() || str.isEmpty());
    }

    private void authenticationPass(String jwt) {
        String id = jwtUtils.getPayloadArguments(jwt).getStr("userId");
        User user = userMapper.selectOneById(Long.parseLong(id));
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), userService.getUserAuthorityById(user.getId()));
        SecurityContextHolder.getContext().setAuthentication(token);
    }
}
